1 module d_tree_sitter.node;
2 
3 extern (C):
4 
5 import d_tree_sitter.language;
6 import d_tree_sitter.tree_cursor;
7 import d_tree_sitter.tree_visitor;
8 import d_tree_sitter.other;
9 
10 import std : iota, Nullable;
11 import std..string : fromStringz, toStringz;
12 
13 /** A single `Node` within a syntax `Tree`. */
14 struct Node
15 {
16   import d_tree_sitter.libc : TSNode, ts_node_symbol, ts_node_type, ts_tree_language,
17     ts_node_is_named, ts_node_is_extra, ts_node_has_changes, ts_node_has_error,
18     ts_node_is_missing, ts_node_start_byte, ts_node_end_byte,
19     ts_node_start_point, ts_node_end_point, ts_node_child, ts_node_child_count,
20     ts_node_named_child, ts_node_named_child_count, ts_node_child_by_field_name,
21     ts_node_child_by_field_id, ts_node_parent, ts_node_next_sibling, ts_node_prev_sibling,
22     ts_node_next_named_sibling,
23     ts_node_prev_named_sibling,
24     ts_node_descendant_for_byte_range,
25     ts_node_named_descendant_for_byte_range,
26     ts_node_descendant_for_point_range, ts_node_named_descendant_for_point_range,
27     ts_node_string, ts_tree_cursor_new, ts_node_edit, ts_node_is_null;
28 
29   /** The internal `TSNode` */
30   TSNode tsnode;
31 
32   /** Create a new Node.
33     Throws:
34       If the passed tsnode is null, it will trigger an error in the debug mode.
35   */
36   this(TSNode tsnode) @nogc nothrow
37   {
38     debug
39     {
40       assert(!ts_node_is_null(tsnode), "The given tsnode is null");
41     }
42     this.tsnode = tsnode;
43   }
44 
45   /**  Creates a new Node from the given nullable TSNode
46 
47     Params:
48       tsnode = a C tsnode, which can be a `null` node.
49 
50     Returns:
51       a `Nullable!Node`, which gives the node if it is not a `null` node, and `null` if it is.
52   */
53   static Nullable!Node create(TSNode tsnode) @trusted @nogc nothrow
54   {
55     if (!ts_node_is_null(tsnode))
56     {
57       return Nullable!Node(Node(tsnode));
58     }
59     else
60     {
61       return Nullable!Node.init;
62     }
63   }
64 
65   /** Check if the Node is a `null` node.
66 
67     Note:
68       this function should be only used when creating a `Node` with its constructor in the release mode (instead of using `Node.create`).
69       All the methods of `Node` already use `Node.create` and return a `Nullable!Node`.
70   */
71   bool isNull()
72   {
73     return ts_node_is_null(tsnode);
74   }
75 
76   /**
77     Get a numeric id for this node that is unique.
78 
79     Within a given syntax tree, no two nodes have the same id. However, if
80     a new tree is created based on an older tree, and a node from the old
81     tree is reused in the process, then that node will have the same id in
82     both trees.
83   */
84   auto id() const @nogc nothrow
85   {
86     return tsnode.id;
87   }
88 
89   /** Get this node's type as a numerical id. */
90   auto kind_id() const @nogc nothrow
91   {
92     return ts_node_symbol(tsnode);
93   }
94 
95   /** Get this node's type as a string. */
96   auto kind() const @nogc nothrow
97   {
98     return fromStringz(ts_node_type(tsnode));
99   }
100 
101   /** Get the [Language] that was used to parse this node's syntax tree. */
102   auto language() const @nogc nothrow
103   {
104     return Language(ts_tree_language(tsnode.tree));
105   }
106 
107   /**
108     Check if this node is *named*.
109 
110     Named nodes correspond to named rules in the grammar, whereas *anonymous* nodes
111     correspond to string literals in the grammar.
112   */
113   auto is_named() const @nogc nothrow
114   {
115     return ts_node_is_named(tsnode);
116   }
117 
118   /**
119     Check if this node is *extra*.
120 
121     Extra nodes represent things like comments, which are not required the grammar,
122     but can appear anywhere.
123   */
124   auto is_extra() const @nogc nothrow
125   {
126     return ts_node_is_extra(tsnode);
127   }
128 
129   /**
130     Check if this node has been edited
131   */
132   auto has_changes() const @nogc nothrow
133   {
134     return ts_node_has_changes(tsnode);
135   }
136 
137   /**
138     Check if this node represents a syntax error or contains any syntax errors anywhere
139     within it.
140   */
141   auto has_error() const @nogc nothrow
142   {
143     return ts_node_has_error(tsnode);
144   }
145 
146   /**
147     Check if this node represents a syntax error.
148 
149     Syntax errors represent parts of the code that could not be incorporated into a
150     valid syntax tree.
151   */
152   auto is_error() const @nogc nothrow
153   {
154     return kind_id() == ushort.max;
155   }
156 
157   /**
158     Check if this node is *missing*.
159 
160     Missing nodes are inserted by the parser in order to recover from certain kinds of
161     syntax errors.
162   */
163   auto is_missing() const @nogc nothrow
164   {
165     return ts_node_is_missing(tsnode);
166   }
167 
168   /**
169     Get the byte offsets where this node starts
170   */
171   auto start_byte() const @nogc nothrow
172   {
173     return ts_node_start_byte(tsnode);
174   }
175 
176   /**
177     Get the byte offsets where this node end.
178   */
179   auto end_byte() const @nogc nothrow
180   {
181     return ts_node_end_byte(tsnode);
182   }
183 
184   /**
185     Get the byte range of source code that this node represents.
186   */
187   auto byte_range() const @nogc nothrow
188   {
189     return iota(start_byte(), end_byte());
190   }
191 
192   /**
193     Get this node's start position in terms of rows and columns.
194   */
195   auto start_position() const @nogc nothrow
196   {
197     return ts_node_start_point(tsnode);
198   }
199 
200   /**
201     Get this node's end position in terms of rows and columns.
202   */
203   auto end_position() const @nogc nothrow
204   {
205     return ts_node_end_point(tsnode);
206   }
207 
208   /**
209     Get the range of source code that this node represents, both in terms of raw bytes
210     and of row/column coordinates.
211   */
212   auto range() const @nogc nothrow
213   {
214     return Range(start_position(), end_position(), start_byte(), end_byte());
215   }
216 
217   /**
218     Get the node's child at the given index, where zero represents the first
219     child.
220 
221     This method is fairly fast, but its cost is technically log(child_index), so you
222     if you might be iterating over a long list of children, you should use
223     [Node::children] instead.
224 
225     Returns:
226       A `Nulllable!Node`
227   */
228   auto child(size_t child_index) const @nogc nothrow
229   {
230     return Node.create(ts_node_child(tsnode, cast(uint)(child_index)));
231   }
232 
233   /**
234     Get this node's number of children
235   */
236   auto child_count() const @nogc nothrow
237   {
238     return ts_node_child_count(tsnode);
239   }
240 
241   /**
242     Get this node's *named* child at the given index.
243 
244     See also [Node::is_named].
245     This method is fairly fast, but its cost is technically log(i), so you
246     if you might be iterating over a long list of children, you should use
247     [Node::named_children] instead.
248 
249     Returns:
250       A `Nulllable!Node`
251   */
252   auto named_child(size_t i) const @nogc nothrow
253   {
254     return Node.create(ts_node_named_child(tsnode, cast(uint)(i)));
255   }
256 
257   /**
258     Get this node's number of *named* children.
259 
260     See also [Node::is_named].
261   */
262   auto named_child_count() const @nogc nothrow
263   {
264     return ts_node_named_child_count(tsnode);
265   }
266 
267   /**
268     Get the first child with the given field name.
269 
270     If multiple children may have the same field name, access them using
271     [children_by_field_name](Node::children_by_field_name)
272 
273     Returns:
274       A `Nulllable!Node`
275   */
276   auto child_by_field_name(string field_name) const
277   {
278     // convert to c string
279     auto field_name_c = toStringz(field_name);
280     auto field_name_length = cast(uint)(field_name.length);
281     return Node.create(ts_node_child_by_field_name(tsnode, field_name_c, field_name_length));
282   }
283 
284   /**
285     Get the first child with the given field name.
286 
287     If multiple children may have the same field name, access them using
288     [children_by_field_name](Node::children_by_field_name)
289 
290     Returns:
291       A `Nulllable!Node`
292   */
293   auto child_by_field_id(ushort field_id) const @nogc nothrow
294   {
295     return Node.create(ts_node_child_by_field_id(tsnode, field_id));
296   }
297 
298   /**  Iterate over this node children.
299 
300       A [TreeCursor] is used to retrieve the children efficiently. Obtain
301       a [TreeCursor] by calling [Tree::walk] or [Node::walk]. To avoid unnecessary
302       allocations, you should reuse the same cursor for subsequent calls to
303       this method.
304 
305       If you're walking the tree recursively, you may want to use the `TreeCursor`
306       APIs directly instead.
307   */
308   auto children(TreeCursor* cursor) const @nogc nothrow
309   {
310     return NodeChildren(this, cursor);
311   }
312 
313   /**  Iterate over this node named children.
314 
315       See also [Node::children].
316   */
317   auto named_children(TreeCursor* cursor) const @nogc nothrow
318   {
319     return NodeNamedChildren(this, cursor);
320   }
321 
322   /**  Iterate over this node children with a given field id.
323 
324       See also [Node::children_by_field_name].
325   */
326   auto children_by_field_id(ushort field_id, TreeCursor* cursor) const @nogc nothrow
327   {
328     return NodeChildrenByFieldID(this, field_id, cursor);
329   }
330 
331   /**  Iterate over this node children with a given field name.
332 
333       See also [Node::children].
334   */
335   auto children_by_field_name(string field_name, TreeCursor* cursor) const
336   {
337     auto field_id = language().field_id_for_name(field_name);
338     return children_by_field_id(field_id, cursor);
339   }
340 
341   /** Check if the node has a immediate parent
342     Note:
343      `parent` method already does this check
344   */
345   auto has_parent() const @nogc nothrow
346   {
347     auto maybe_parent = ts_node_parent(tsnode);
348     return !ts_node_is_null(maybe_parent);
349   }
350 
351   /**  Get this node immediate parent.
352 
353     Returns:
354       a `Nullable!Node`, which gives the parent node if it has a parent, and `null` if the node has no parent.
355   */
356   auto parent() const @nogc nothrow
357   {
358     return Node.create(ts_node_parent(tsnode));
359   }
360 
361   /** Find the nth parent of node. It goes up until it hits a null parent or `max_nth`.
362     Params:
363       node = the node
364       max_nth = the maximum level to go up.
365     Returns:
366       A node. If the given node doesn't have a parent, it returns the node itself.
367     Note: the nth might not be reached if there are no more parents.
368   */
369   auto nth_parent(in uint max_nth = 2) @nogc nothrow @trusted const
370   {
371     auto maybeFirstParent = this.parent();
372     if (maybeFirstParent.isNull())
373     {
374       // return the node itself
375       return this;
376     }
377     auto parent = maybeFirstParent.get();
378 
379     uint nth = 1;
380     while (nth != max_nth)
381     {
382       auto maybe_parent = parent.parent();
383       if (!maybe_parent.isNull())
384       {
385         parent = maybe_parent.get();
386       }
387       else
388       {
389         break;
390       }
391       ++nth;
392     }
393     return parent;
394   }
395 
396   /** Check if the node has a next sibling.
397     Note:
398      `next_sibling` method already does this check
399   */
400   auto has_next_sibling() const @nogc nothrow
401   {
402     auto maybeNode = ts_node_next_sibling(tsnode);
403     return !ts_node_is_null(maybeNode);
404   }
405 
406   /**  Get this node next sibling.
407     Returns:
408       A `Nulllable!Node`
409   */
410   auto next_sibling() const @nogc nothrow
411   {
412     return Node.create(ts_node_next_sibling(tsnode));
413   }
414 
415   /** Check if the node has a previous sibling.
416     Note:
417      `prev_sibling` method already does this check
418   */
419   auto has_prev_sibling() const @nogc nothrow
420   {
421     auto maybeNode = ts_node_prev_sibling(tsnode);
422     return !ts_node_is_null(maybeNode);
423   }
424 
425   /**  Get this node previous sibling.
426 
427     Returns:
428       A `Nulllable!Node`
429   */
430   auto prev_sibling() const @nogc nothrow
431   {
432     return Node.create(ts_node_prev_sibling(tsnode));
433   }
434 
435   /**  Get this node next named sibling.
436 
437     Returns:
438       A `Nulllable!Node`
439   */
440   auto next_named_sibling() const @nogc nothrow
441   {
442     return Node.create(ts_node_next_named_sibling(tsnode));
443   }
444 
445   /**  Get this node previous named sibling.
446 
447     Returns:
448       A `Nulllable!Node`
449    */
450   auto prev_named_sibling() const @nogc nothrow
451   {
452     return Node.create(ts_node_prev_named_sibling(tsnode));
453   }
454 
455   /**  Get the smallest node within this node that spans the given range.
456 
457     Returns:
458       A `Nulllable!Node`
459   */
460   auto descendant_for_byte_range(uint start, uint end) const @nogc nothrow
461   {
462     return Node.create(ts_node_descendant_for_byte_range(tsnode, start, end));
463   }
464 
465   /**  Get the smallest named node within this node that spans the given range.
466 
467     Returns:
468       A `Nulllable!Node`
469   */
470   auto named_descendant_for_byte_range(uint start, uint end) const @nogc nothrow
471   {
472     return Node.create(ts_node_named_descendant_for_byte_range(tsnode, start, end));
473   }
474 
475   /**  Get the smallest node within this node that spans the given range.
476 
477     Returns:
478       A `Nulllable!Node`
479   */
480   auto descendant_for_point_range(Point start, Point end) const @nogc nothrow
481   {
482     return Node.create(ts_node_descendant_for_point_range(tsnode, start, end));
483   }
484 
485   /**  Get the smallest named node within this node that spans the given range.
486 
487     Returns:
488       A `Nulllable!Node`
489   */
490   auto named_descendant_for_point_range(Point start, Point end) const @nogc nothrow
491   {
492     return Node.create(ts_node_named_descendant_for_point_range(tsnode, start, end));
493   }
494 
495   /** Convert Node to string */
496   auto to_string() const nothrow
497   {
498     import core.memory : pureFree;
499 
500     auto c_string = ts_node_string(tsnode); // NOTE requires freeing the heap allocated string
501     string str = fromStringz(c_string).dup; // TODO use automem instead of copying and freeing the original?
502     pureFree(c_string);
503     return str;
504   }
505 
506   alias to_sexp = to_string;
507 
508   import std..string : assumeUTF;
509 
510   /** Convert Node to utf8 string */
511   auto utf8_text(string source_code) const @nogc nothrow
512   {
513     import std : representation;
514 
515     const source = source_code.representation();
516     return assumeUTF(source[start_byte() .. end_byte()]);
517   }
518 
519   /// ditto
520   auto utf8_text(ubyte[] source) const @nogc nothrow
521   {
522     return assumeUTF(source[start_byte() .. end_byte()]);
523   }
524 
525   /** Convert Node to utf16 string */
526   auto utf16_text(ushort[] source) const @nogc nothrow
527   {
528     return assumeUTF(source[start_byte() .. end_byte()]);
529   }
530 
531   /**  Create a new [TreeCursor] starting from this node. */
532   auto walk() const @nogc nothrow
533   {
534     return TreeCursor(ts_tree_cursor_new(tsnode));
535   }
536 
537   /** Hash a node. This returns a unique string for this node. */
538   auto hash() @trusted const @nogc
539   {
540     import bc..string : nogcFormat;
541 
542     return nogcFormat!"%d%d"(this.kind_id(), this.start_byte());
543   }
544 
545   /**
546     Traverse this `Node` and all its descendants in a top-down left to right manner while
547     applying the visitor at each [Node].
548   */
549   void traverse(TreeVisitor visitor) const
550   {
551     auto cursor = walk();
552     visitor.enter_node(&cursor);
553     auto recurse = true;
554     while (true)
555     {
556       if (recurse && cursor.goto_first_child())
557       {
558         recurse = visitor.enter_node(&cursor);
559       }
560       else
561       {
562         visitor.leave_node(&cursor);
563         if (cursor.goto_next_sibling())
564         {
565           recurse = visitor.enter_node(&cursor);
566         }
567         else if (cursor.goto_parent())
568         {
569           recurse = false;
570         }
571         else
572         {
573           break;
574         }
575       }
576     }
577   }
578 
579   /**
580     Traverse this `Node` and all its descendants in a top-down left to right manner while
581     applying the visitor at each [Node].
582 
583     NOTE: if you are sure that TreeVisitor is nothrow, you can use this method
584   */
585   void traverse_nothrow(TreeVisitor visitor) const nothrow
586   {
587     import std : assumeWontThrow;
588 
589     assumeWontThrow(traverse(visitor));
590   }
591 
592   /**  Edit this node to keep it in-sync with source code that has been edited.
593 
594       This function is only rarely needed. When you edit a syntax tree with the
595       [Tree::edit] method, all of the nodes that you retrieve from the tree
596       afterward will already reflect the edit. You only need to use [Node::edit]
597       when you have a specific [Node] instance that you want to keep and continue
598       to use after an edit.
599   */
600   auto edit(const InputEdit* edit) @nogc nothrow
601   {
602     return ts_node_edit(&tsnode, edit);
603   }
604 }
605 
606 /**  A range to iterate over the node children.
607 
608     A [TreeCursor] is used to retrieve the children efficiently. Obtain
609     a [TreeCursor] by calling [Tree::walk] or [Node::walk]. To avoid unnecessary
610     allocations, you should reuse the same cursor for subsequent calls to
611     this method.
612 
613     If you're walking the tree recursively, you may want to use the `TreeCursor`
614     APIs directly instead.
615 */
616 struct NodeChildren
617 {
618   private TreeCursor* cursor;
619 
620   private const uint count;
621   private uint iChild = 0;
622 
623   /** create a NodeChildren for the given node and cursor */
624   auto this(Node parent, TreeCursor* cursor) @nogc nothrow
625   {
626     this.cursor = cursor;
627 
628     cursor.reset(parent);
629     cursor.goto_first_child();
630     this.count = parent.child_count();
631   }
632 
633   /** Get the current child */
634   auto front() const @nogc nothrow
635   {
636     return cursor.node();
637   }
638 
639   /** go to the next child */
640   void popFront() @nogc nothrow
641   {
642     cursor.goto_next_sibling();
643     iChild++;
644   }
645 
646   /** Is it the end? */
647   auto empty() const @nogc nothrow
648   {
649     return iChild == count;
650   }
651 }
652 
653 /**  A range the iterates over the node named children.
654 
655     See also [Node::children].
656 */
657 struct NodeNamedChildren
658 {
659   private TreeCursor* cursor;
660 
661   private const uint count;
662   private uint iChild = 0;
663 
664   /** create a NodeNamedChildren for the given node and cursor */
665   auto this(Node parent, TreeCursor* cursor) @nogc nothrow
666   {
667     this.cursor = cursor;
668 
669     cursor.reset(parent);
670     cursor.goto_first_child();
671     this.count = parent.named_child_count();
672   }
673 
674   /** Finds the front node */
675   private void preFront() @nogc nothrow
676   {
677     while (!cursor.node().is_named())
678     {
679       if (!cursor.goto_next_sibling())
680       {
681         break;
682       }
683     }
684   }
685 
686   /**
687     Get the current child
688     NOTE Do not call this twice in a row without calling popFront and empty in between!
689   */
690   auto front() @nogc nothrow
691   {
692     preFront();
693     return cursor.node();
694   }
695 
696   /** go to the next child */
697   void popFront() @nogc nothrow
698   {
699     cursor.goto_next_sibling();
700     iChild++;
701   }
702 
703   /** Is it the end? */
704   auto empty() const @nogc nothrow
705   {
706     return iChild == count;
707   }
708 }
709 
710 /**  A range to iterate over the node children with a given field id.
711 
712     See also [Node::children_by_field_name].
713 */
714 struct NodeChildrenByFieldID
715 {
716   private TreeCursor* cursor;
717   private ushort field_id;
718 
719   private bool noMoreNextSibiling = false;
720 
721   /** create a NodeChildrenByFieldID for the given node, field_id, and cursor */
722   auto this(Node parent, ushort field_id, TreeCursor* cursor) @nogc nothrow
723   {
724     this.cursor = cursor;
725     this.field_id = field_id;
726 
727     cursor.reset(parent);
728     cursor.goto_first_child();
729   }
730 
731   /** Finds the front node */
732   private void preFront() @nogc nothrow
733   {
734     // find the node related to field_id
735     while (cursor.field_id() != field_id)
736     {
737       popFront();
738     }
739   }
740 
741   /**
742     Get the current child
743     NOTE Do not call this twice in a row without calling popFront and empty in between!
744   */
745   auto front() @nogc nothrow
746   {
747     preFront();
748     return cursor.node();
749   }
750 
751   /** go to the next child */
752   void popFront() @nogc nothrow
753   {
754     // check if this found field_id is the last one
755     if (!cursor.goto_next_sibling())
756     {
757       // if no next sibiling then we are done finding
758       noMoreNextSibiling = true;
759     }
760   }
761 
762   /** Is it the end? */
763   auto empty() const @nogc nothrow
764   {
765     return noMoreNextSibiling;
766   }
767 }